package com.usyk;

import com.usyk.util.Party;
import org.apache.commons.io.FileUtils;

import java.io.*;
import java.util.*;

/**
 * User: oleksii.usyk@gmail.com
 * Date: 04.01.12
 * Time: 20:27
 */
public class Model {

    public static Level createHeadLevelFromDirectory(String directory) throws IOException {

        File container = new File(directory);

        if (!container.isDirectory()) {
            throw new IllegalArgumentException("directory " + container.getAbsolutePath() + " should be directory!");
        }

        Level level = new Level();
        level.setName(container.getName());

        File[] ratingFiles = container.listFiles(new FilenameFilter() {
            @Override
            public boolean accept(File dir, String name) {
                return name.equals("rating.csv");
            }
        });


        if (ratingFiles.length == 1) {

            String[] children = container.list(new FilenameFilter() {
                @Override
                public boolean accept(File dir, String name) {
                    return !name.equals("rating.csv") && !name.equals(".svn");
                }
            });

            level.setNextLevelsRating(RatingParser.parse(ratingFiles[0], Arrays.asList(children)));
            if (children.length == 0) {
                return level;
            }

            Set<Level> childLevels = new HashSet<Level>();
            for (String child : children) {
                String path = container.getCanonicalPath() + '/' + child;
                if (new File(path).isDirectory()) {
                    //directory
                    childLevels.add(createHeadLevelFromDirectory(path));
                } else {
                    //file
                    childLevels.add(createFromFile(path));
                }
            }
            level.modifyKeys(childLevels);


        } else {
            throw new IllegalArgumentException("Every directory should contain only 1 rating.csv file");
        }

        return level;
    }

    public static Level createFromFile(String filename) throws IOException {


        return null;
    }

    public static Map<String, Party> configureParties(String configDirectory) throws IOException {
        Map<String, Party> resultParties = new HashMap<String, Party>();
        File finFile = new File(configDirectory + "/fin.csv");
        List<String> lines = FileUtils.readLines(finFile);

        //creating parties and adding fin resources
        for (String line : lines) {
            String[] items = line.split(",");
            Party party = new Party();
            party.setName(items[0]);
            party.setFinResource(Double.valueOf(items[1]));
            if (resultParties.containsKey(party)) {
                throw new IllegalArgumentException("Duplicate party : '" + party.getName() + "' in file "
                        + configDirectory + "/fin.csv");
            }
            resultParties.put(items[0], party);
        }

        //adding views to parties
        File viewsFile = new File(configDirectory + "/views.csv");
        lines = FileUtils.readLines(viewsFile);
        //read header
        String[] viewName = lines.get(0).split(",");

        for (int i = 1; i < lines.size(); i++) {
            String[] items = lines.get(i).split(",");
            Map<String, Double> views = new HashMap<String, Double>(4);
            for (int j = 1; j < items.length; j++) {
                views.put(viewName[j], Double.valueOf(items[j]));
            }
            resultParties.get(items[0]).setViews(views);
        }

        //adding personal and admin resource to parties
        File[] regionFolders = new File(configDirectory).listFiles(new FilenameFilter() {
            @Override
            public boolean accept(File dir, String name) {
                return !name.contains(".");
            }
        });
        for (File regionFolder : regionFolders) {

            File adminFile = new File(regionFolder.getAbsolutePath() + "/admin.csv");
            lines = FileUtils.readLines(adminFile);

            for (int i = 0; i < lines.size(); i++) {
                String[] items = lines.get(i).split(",");
                if (resultParties.get(items[0]).getAdminResourcePerRegion() == null) {
                    resultParties.get(items[0]).setAdminResourcePerRegion(new HashMap<String, Double>());
                }
                resultParties.get(items[0]).getAdminResourcePerRegion().put(regionFolder.getName(), Double.valueOf(items[1]));
            }

            File personalFile = new File(regionFolder.getAbsolutePath() + "/personal.csv");
            lines = FileUtils.readLines(personalFile);

            for (int i = 0; i < lines.size(); i++) {
                String[] items = lines.get(i).split(",");
                if (resultParties.get(items[0]).getPersonalResourcePerRegion() == null) {
                    resultParties.get(items[0]).setPersonalResourcePerRegion(new HashMap<String, Double>());
                }
                resultParties.get(items[0]).getPersonalResourcePerRegion().put(regionFolder.getName(), Double.valueOf(items[1]));
            }


        }


        return resultParties;
    }

    /**
     * coalitions contains strings like BUT+NASHAUKR, where "+" means coalition
     *
     * @param allParties
     * @param headLevel
     * @param coalitions
     * @return
     */
    public static Level createLevelForCoalition(Map<String, Party> allParties, Level headLevel, List<String> coalitions) {

        Map<String, Party> metaParties = new HashMap<String, Party>();
        for (String coalition : coalitions) {
            String[] participants = coalition.split("\\+");
            Party metaParty = new Party();
            metaParty.setName(coalition);
            Double fin = 0d;
            for (String party : participants) {
                fin += allParties.get(party).getFinResource();
            }
            HashMap<String, Double> views = new HashMap<String, Double>();

            //weighted average (personal resource is used)
            for (String view : allParties.get(participants[0]).getViews().keySet()) {
                Double viewSum = 0d;
                for (String party : participants) {
                    viewSum += allParties.get(party).getViews().get(view) * allParties.get(party).getFinResource() / fin;
                }
                views.put(view, viewSum);
            }

            //sum of admin resource
            HashMap<String, Double> adminResourcePerRegion = new HashMap<String, Double>();
            for (String admin : allParties.get(participants[0]).getAdminResourcePerRegion().keySet()) {
                Double adminSum = 0d;
                for (String party : participants) {
                    adminSum += allParties.get(party).getAdminResourcePerRegion().get(admin);
                }
                adminResourcePerRegion.put(admin, adminSum);
            }

            //personal rating
            //todo coefficient
            HashMap<String, Double> personalResourcePerRegion = new HashMap<String, Double>();
            for (String personal : allParties.get(participants[0]).getPersonalResourcePerRegion().keySet()) {
                Double personalSum = 0d;
                for (String party : participants) {
                    personalSum += allParties.get(party).getPersonalResourcePerRegion().get(personal);
                }
                personalResourcePerRegion.put(personal, personalSum);
            }

            metaParty.setViews(views);
            metaParty.setAdminResourcePerRegion(adminResourcePerRegion);
            metaParty.setPersonalResourcePerRegion(personalResourcePerRegion);
            metaParty.setFinResource(fin);
            metaParties.put(metaParty.getName(), metaParty);
        }

        // for each region
        for (Level regionLevel : headLevel.getNextLevelsRating().keySet()) {
            String regionName = regionLevel.getName();
            // for each (view, resource)
            for (Level resLevel : regionLevel.getNextLevelsRating().keySet()) {
                String resName = resLevel.getName();

                if ("view".equalsIgnoreCase(resName)) {
                    // (kom, cen, dem, rig)
                    for (Level level : resLevel.getNextLevelsRating().keySet()) {
                        level.setNextLevelsRating(null);
                        String viewName = level.getName();
                        Double sum = 0d;
                        for (Party party : metaParties.values()) {
                            sum += party.getViews().get(viewName);
                        }
                        for (Party party : metaParties.values()) {
                            Level partyLevel = new Level();
                            partyLevel.setName(party.getName());
                            if (level.getNextLevelsRating() == null) {
                                level.setNextLevelsRating(new HashMap<Level, Double>());
                            }
                            level.getNextLevelsRating().put(partyLevel, party.getViews().get(viewName) / sum);
                        }

                    }
                }
                if ("resourse".equalsIgnoreCase(resName)) {
                    // (fin, adm, pers)

                    for (Level level : resLevel.getNextLevelsRating().keySet()) {
                        level.setNextLevelsRating(null);
                        if ("admin".equalsIgnoreCase(level.getName())) {
                            String viewName = level.getName();
                            Double sum = 0d;
                            for (Party party : metaParties.values()) {
                                sum += party.getAdminResourcePerRegion().get(regionName);
                            }
                            for (Party party : metaParties.values()) {
                                Level partyLevel = new Level();
                                partyLevel.setName(party.getName());
                                if (level.getNextLevelsRating() == null) {
                                    level.setNextLevelsRating(new HashMap<Level, Double>());
                                }
                                level.getNextLevelsRating().put(partyLevel, party.getAdminResourcePerRegion().get(regionName) / sum);
                            }
                        }
                        if ("personal".equalsIgnoreCase(level.getName())) {
                            String viewName = level.getName();
                            Double sum = 0d;
                            for (Party party : metaParties.values()) {
                                sum += party.getPersonalResourcePerRegion().get(regionName);
                            }
                            for (Party party : metaParties.values()) {
                                Level partyLevel = new Level();
                                partyLevel.setName(party.getName());
                                if (level.getNextLevelsRating() == null) {
                                    level.setNextLevelsRating(new HashMap<Level, Double>());
                                }
                                level.getNextLevelsRating().put(partyLevel, party.getPersonalResourcePerRegion().get(regionName) / sum);
                            }
                        }
                        if ("fin".equalsIgnoreCase(level.getName())) {
                            String viewName = level.getName();
                            Double sum = 0d;
                            for (Party party : metaParties.values()) {
                                sum += party.getFinResource();
                            }
                            for (Party party : metaParties.values()) {
                                Level partyLevel = new Level();
                                partyLevel.setName(party.getName());
                                if (level.getNextLevelsRating() == null) {
                                    level.setNextLevelsRating(new HashMap<Level, Double>());
                                }
                                level.getNextLevelsRating().put(partyLevel, party.getFinResource() / sum);
                            }
                        }
                    }
                }


            }


        }
        return headLevel;
    }

    public static void main(String[] args) throws IOException {

        Map<String, Party> parties = configureParties("D:\\projects\\diploma-usyk-2012\\src\\main\\resources\\partiesconfig");

        Level level = createHeadLevelFromDirectory("D:\\projects\\diploma-usyk-2012\\src\\main\\resources\\result");
        System.out.println("level = " + level);

        level = createLevelForCoalition(parties,level,Arrays.asList("BUT","PR","NASHAUKR","NPU","UDAR","FRONT","SYLNAUKR","SVOBODA","SPU","KPU"));
        System.out.println("results = " + level.getResult());
        List<Double> sortedList = new ArrayList<Double>(level.getResult().values().size());
        for (Double d : level.getResult().values()){
            sortedList.add(d);
        }
        Collections.sort(sortedList,Collections.reverseOrder());

        System.out.println("sortedList = " + sortedList);
        
        
        level = createLevelForCoalition(parties,level,Arrays.asList("BUT+NASHAUKR+FRONT+UDAR","PR","NPU","SYLNAUKR","SVOBODA","SPU","KPU"));

        System.out.println("results = " + level.getResult());
    }

    public static Map<String, Double> processModel(Level root) {

        //root.get
        return null;
    }

}
